(** Bombs-Must-Detonate: Compiler
    @author Brian Go *)

(** Usage:
    "bmdc [src-file] [output-file]"
      Outputs the compilation result of src-file to output-file.
      The source-to-source compilation result is stored in temp.bmd.  Note this 
      is purely for debugging purposes; we do *not* re-parse this file.
    "bmdc [src-file]"
      Same as above, but prints to stdout instead of an output file. *)
    
let main () =
  let ast = ref [] in
  try
    let inchan = if Sys.argv.(1) = "stdin" then stdin else open_in (Sys.argv.(1)) in
    let lexbuf = Lexing.from_channel inchan in
    let _ = (print_string (String.concat "" ["\nBeginning parse of file: ";(Sys.argv.(1));"\n"])); flush stdout; in
    let _ = ast := Bmdparse.program Bmdlex.bmd_lang lexbuf in
    let _ = print_string "Compiling state machines...\n"; flush stdout; in
    let _ = ast := Bmdfsmc.compile_fsm !ast in
      (** Output the compiled fsm code.  We do *not* re-parse,
	 this is just for debugging. **)
    let src_to_src_file = open_out "temp.bmd" in
    let _ = output_string src_to_src_file (Ast.string_of_ast !ast) in  
    let _ = Bmdtc.reset_link_buffer in
    let _  = print_string "Type checking...\n"; flush stdout in
    let is_typed = Bmdtc.is_typed !ast in
      if is_typed then
	let _ = print_string "Compiling...\n"; flush stdout; in
	let ir_buf = Bmdirc.compile_ir !ast in
	let final_buf = Bmdfc.compile_buffer ir_buf in
	let do_file_output = ((Array.length Sys.argv) >= 3) in
	let outfile = if do_file_output then open_out Sys.argv.(2) else stdout in
	let _ = output_string outfile (Bmdtc.get_link_buffer()) in
	let _ = Bmdfc.print_buffer outfile final_buf in
	let _ = print_string "Done.\n"; flush stdout in
	  ()
      else
	let _ = print_string "Typecheck failure.\n"; flush stdout; in
	  ()
  with
      Parsing.Parse_error -> 
	begin 
	  print_string "Syntax error on line ";
	  print_string (string_of_int !Bmdlex.line_count);
	  print_string ".\n";
	  flush stdout; 
	end
    | Failure s ->
	begin
	  print_string "Failure: ";
	  print_string s;
	  print_string "\n";
	  flush stdout;
	end
    | Sys_error s ->
	begin
	  print_string "Could not open input file ";
	  print_string s;
	  print_string "\n";
	  flush stdout;
	end 
    | Bmdfsmc.Fsm_error s ->
	begin
	  print_string s;
	  print_string "\n";
	  flush stdout;
	end 
    | _ ->
	begin
	  print_string "Compilation failed.\n";
	end 
let _ = main()
